package com.dream.dao.base;

/**
 * 
 * @author Evan
 * @date 2013-8-25
 * 
 */
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.springframework.stereotype.Repository;

import com.dream.model.app.AppAbstractUser.UserStatus;
import com.dream.model.app.AppPosition.PositionType;
import com.dream.model.app.AppUser;
import com.dream.model.app.AppUserGroup;
import com.dream.utils.hibernate.DetachedCriteriaBuilder;
import com.dream.utils.hibernate.DreamBaseDAO;
import com.dream.utils.hibernate.PagingVO;
import com.dream.vo.app.UserVO;
import com.google.common.collect.Lists;

@Repository
public class AppUserDAO extends DreamBaseDAO<AppUser> {
	
	/**
	 * 
	 * @author evan
	 * @Revision
	 * @date 2013-9-8
	 * @param id
	 * @param password
	 * @return
	 */
	public AppUser login(String id, String password){
		
		DetachedCriteriaBuilder builder = DetachedCriteriaBuilder.instance(AppUser.class);
		builder.addEq("status",UserStatus.active);
		builder.addEq("id", id);
		builder.addEq("password", password);
		return selectTopOne(builder);
		
	}
	
	
	/**
	 * 
	 * @copyright evan
	 * @author evan
	 * @date 2013-9-4
	 * @param deptId
	 * @param positionId
	 * @param groupId
	 * @param userId
	 * @param name
	 * @param pageIndex
	 * @param pageSize
	 * @return
	 */
	public PagingVO queryUser(final UserVO userVO, final PagingVO page){
		
		DetachedCriteriaBuilder queryBuilder = initQueryBuilder(userVO);
		DetachedCriteriaBuilder countBuilder = initQueryBuilder(userVO);
		return this.selectPagingVO(queryBuilder, page, countBuilder);
		
	}
	
	
	/**
	 * 
	 * @copyright evan
	 * @author evan
	 * @date 2013-9-4
	 * @param deptId
	 * @param positionId
	 * @param groupId
	 * @param userId
	 * @param name
	 * @return
	 */
	private DetachedCriteriaBuilder initQueryBuilder(final UserVO userVO){
		
		DetachedCriteriaBuilder builder = DetachedCriteriaBuilder.instance(AppUser.class,"u");
		builder.addEq("positionId", userVO.getPosition());
		builder.addEq("id", userVO.getId()).addLikeStart("name", userVO.getName());
		
		builder.addIn("orgId", userVO.getOrgs());
		
		DetachedCriteria criteria = builder.getDetachedCriteria();
		if(StringUtils.isNotBlank(userVO.getGroup())){
			addUserGroupExist(Lists.newArrayList(userVO.getGroup()),criteria);
		}
		return builder;
		
	}
	
	/**
	 * 
	 * @copyright evan
	 * @author evan
	 * @date 2013-9-7
	 * @param groups
	 * @param detachedCriteria
	 */
	private void addUserGroupExist(final Collection<String> groups,final DetachedCriteria detachedCriteria){
		
		DetachedCriteriaBuilder usrGrpBuilder = DetachedCriteriaBuilder.instance(AppUserGroup.class,"ug");
		usrGrpBuilder.addEq("deleted", false).addIn("groupId", groups);
		usrGrpBuilder.setProjection(Projections.property("ug.id"));
		
		usrGrpBuilder.getDetachedCriteria().add(Restrictions.eqProperty("ug.userId", "u.id"));
		detachedCriteria.add(Subqueries.exists(usrGrpBuilder.getDetachedCriteria()));
		
		
	}
	
	
	/***
	 * 
	 * @author evan
	 * @Revision
	 * @date 2013-9-24
	 * @return
	 */
	public Collection<String> getAllActiveUser(){
		
		DetachedCriteriaBuilder builder = DetachedCriteriaBuilder.instance(AppUser.class,"u");
		builder.addEq("status", UserStatus.active);
		builder.setProjection(Projections.property("id"));
		return this.selectE(builder);
	}
	
	/***
	 * 
	 * @author evan
	 * @Revision
	 * @date 2013-9-24
	 * @return
	 */
	public List<AppUser> getAllUserByStatus(UserStatus status){
		
		DetachedCriteriaBuilder builder = DetachedCriteriaBuilder.instance(AppUser.class,"u");
		builder.addEq("status", status);
		return this.selectE(builder);
	}
	
	/**
	 * 
	 * @author evan
	 * @Revision
	 * @date 2013-10-6
	 * @param deptIds
	 * @param positionId
	 * @return
	 */
	public List<AppUser> queryApprover(final Collection<String> deptIds,final String positionId,final String groupId){
		
		DetachedCriteriaBuilder builder = DetachedCriteriaBuilder.instance(AppUser.class,"u");
		builder.addEq("u.status", UserStatus.active);
		builder.addEq("u.positionId", positionId);
		if(CollectionUtils.isNotEmpty(deptIds)){
			builder.leftJoin("depts", "d");
			builder.addIn("d.orgId", deptIds);
		}
		
		if(StringUtils.isNotBlank(groupId)){
			DetachedCriteriaBuilder subBuilder = DetachedCriteriaBuilder.instance(AppUserGroup.class,"au");
			subBuilder.addEq("au.groupId", groupId).addEq("au.deleted", false);
			subBuilder.setProjection(Projections.property("au.userId"));
			subBuilder.getDetachedCriteria().add(Restrictions.eqProperty("au.userId", "u.id"));
			builder.getDetachedCriteria().add(Subqueries.exists(subBuilder.getDetachedCriteria()));
		}
		return select(builder);
	}
	
	/***
	 * 
	 * @author evan
	 * @Revision
	 * @date 2013-11-23
	 * @param deptId
	 * @param positionType
	 * @return
	 */
	public List<Map<String,Object>> selectUser(String deptId, String positionType) {
		DetachedCriteriaBuilder builder = DetachedCriteriaBuilder.instance(AppUser.class);
		
		builder.addEq("status", UserStatus.active);
		builder.leftJoin("depts", "d").innerJoin("position", "p");
		builder.addEq("d.orgId", deptId).addEq("p.type", PositionType.instance(positionType));

		builder.addAscOrder("d.orgId");
		builder.addAscOrder("positionId");
		builder.addAscOrder("id");
		
		ProjectionList pl = Projections.projectionList();
		pl.add(Projections.property("d.orgId"),"deptId");
		pl.add(Projections.property("positionId"),"posId");
		pl.add(Projections.property("id"),"id");
		pl.add(Projections.property("name"),"name");
		
		builder.setProjection(pl);
		builder.getDetachedCriteria().setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
		return selectE(builder);
		
	}
	
	/**
	 * get by position
	 * @author Tony	
	 * @date 2014-2-17
	 * @param positionType
	 * @return
	 */
	public List<Map<String,Object>> selectUser(String positionType) {
		DetachedCriteriaBuilder builder = DetachedCriteriaBuilder.instance(AppUser.class);
		
		builder.addEq("status", UserStatus.active);
		builder.innerJoin("position", "p");
		builder.addEq("p.type", PositionType.instance(positionType));

		builder.addAscOrder("id");
		
		ProjectionList pl = Projections.projectionList();
		pl.add(Projections.property("id"),"id");
		pl.add(Projections.property("name"),"name");
		
		builder.setProjection(pl);
		builder.getDetachedCriteria().setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
		return selectE(builder);
		
	}
}
